﻿//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web;
using System.Web.UI;
using System.IO;
using System.Globalization;
using System.Web.Script.Serialization;
using System.Text.RegularExpressions;
using System.Web.Caching;

namespace DNA.Mvc.jQuery
{
    /// <summary>
    /// Represents support for rendering html controls,jQuery scripts for jQuery or jQuery CSS Framework in view
    /// </summary>
    public static class jQueryExtensions
    {
        /// <summary>
        /// Register the jquery plugin scripts to start up script event.
        /// </summary>
        /// <param name="helper">The ajax helper object</param>
        /// <param name="selector">Specified the jQuery object selector</param>
        /// <param name="pluginName">Specified the jQuery pluginName name.</param>
        public static void jQuery(this AjaxHelper helper, string selector, string pluginName)
        {
            jQuery(helper, selector, pluginName, null);
        }

        /// <summary>
        /// Add the jQuery scripts to start up script event
        /// </summary>
        /// <param name="helper">The ajax helper object</param>
        /// <param name="selector">Specified the jQuery object selector</param>
        /// <param name="pluginName">Specified the jQuery pluginName name.</param>
        /// <param name="options">Specified the initial options object</param>
        public static void jQuery(this AjaxHelper helper, string selector, string pluginName, object options)
        {
            string _sel = selector;
            if (!selector.StartsWith(".") && (!selector.StartsWith("#")) && (!selector.Equals("body") && (!selector.Equals("document"))))
                _sel = "#" + selector;

            jQueryScriptBuilder builder = new jQueryScriptBuilder(_sel, pluginName, options);
            RegisterStartupScript(helper, builder.ToString());
        }

        /// <summary>
        /// Register the disable selection script for specfied trigger element.
        /// </summary>
        /// <param name="helper">The Ajax helper object extends.</param>
        /// <param name="trigger">The jQuery selector of the tagger element </param>
        public static void DisableSelection(this AjaxHelper helper, string trigger)
        {
            helper.RegisterStartupScript("$('" + trigger + "').disableSelection();");
        }

        /// <summary>
        /// Register the jQuery script to client page load event.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="script">The client script to register.</param>
        public static void RegisterStartupScript(this AjaxHelper helper, string script)
        {
            //string securityScript = "try{" + script + "}catch(e){uiHelper.showMsg('Client script error',e);}";
            //string securityScript = "try{" + script + "}catch(e){alert(e.description);}";
            string securityScript = script;
            if (helper.ViewContext.TempData["StartupScripts"] != null)
                helper.ViewContext.TempData["StartupScripts"] += "\r\n" + securityScript;
            else
                helper.ViewContext.TempData["StartupScripts"] = securityScript;
        }

        public static MvcHtmlString RenderScripts(this HtmlHelper helper)
        {
            StringBuilder resScripts = new StringBuilder();
            if (helper.ViewContext.TempData["ClientRes"] != null)
            {
                IDictionary<string, string> resources = helper.ViewContext.TempData["ClientRes"] as IDictionary<string, string>;
                if (resources != null)
                {

                    List<string> options = new List<string>();

                    foreach (string key in resources.Keys)
                        options.Add(key + ":'" + resources[key] + "'");

                    resScripts.Append("$.extend(portal.res,")
                                .Append("{" + string.Join(",", options.ToArray()) + "}")
                                .Append(");");
                    helper.ViewContext.TempData.Remove("ClientRes");
                }
            }

            if (helper.ViewContext.TempData["StartupScripts"] != null)
            {
                StringBuilder scripts = new StringBuilder();
                scripts.AppendLine("<script type='text/javascript'>");
                scripts.AppendLine("$(function(){");
                if (resScripts.Length > 0)
                    scripts.Append(resScripts.ToString());
                scripts.Append(helper.ViewContext.TempData["StartupScripts"].ToString());
                scripts.AppendLine("});");
                scripts.AppendLine("</script>");
                helper.ViewContext.TempData.Remove("StartupScripts");
                return MvcHtmlString.Create(scripts.ToString());
            }
            return MvcHtmlString.Empty; 
        }

        #region jQuery UI

        /// <summary>
        /// Register the jQuery UI Tabs plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        public static void Tabs(this AjaxHelper helper, string targetSelector)
        {
            helper.Tabs(targetSelector, null);
        }

        /// <summary>
        /// Register the jQuery UI Tabs plugin script
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        /// <param name="options"></param>
        public static void Tabs(this AjaxHelper helper, string targetSelector, TabsOptions options)
        {
            helper.jQuery(targetSelector, "tabs", options);
        }

        /// <summary>
        ///  Returns the html element and register the progressbar jQuery ui javascript.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="name">Specified the progressbar name.</param>
        /// <param name="value">Specified the initialize value.</param>
        /// <returns></returns>
        public static MvcHtmlString Progressbar(this AjaxHelper helper, string name, int value)
        {
            return helper.Progressbar(name, value, "", null);
        }

        /// <summary>
        /// Returns the html element and register the progressbar jQuery ui javascript.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="name">Specified the progressbar name.</param>
        /// <param name="value">Specified the initialize value.</param>
        /// <param name="onChange">The clicent handler of the onchange event.</param>
        /// <returns></returns>
        public static MvcHtmlString Progressbar(this AjaxHelper helper, string name, int value, string onChange)
        {
            return helper.Progressbar(name, value, onChange, null);
        }

        /// <summary>
        /// Returns the html element and register the progressbar jQuery ui javascript.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="name">Specified the progressbar name.</param>
        /// <param name="value">Specified the initialize value.</param>
        /// <param name="onChange"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static MvcHtmlString Progressbar(this AjaxHelper helper, string name, int value, string onChange, object htmlAttributes)
        {
            var opts = new jQueryScriptBuilder("#" + name, "progressbar");
            var progbar = new TagBuilder("div");
            opts.AddOption("value", value);
            if (!string.IsNullOrEmpty(onChange))
                opts.AddFunctionOption("change", onChange, new string[] { "event", "ui" });
            //progbar.GenerateId(name);
            progbar.Attributes.Add("id", name);
            if (htmlAttributes != null)
                progbar.MergeAttributes<string, object>(ObjectHelper.ConvertObjectToDictionary(htmlAttributes));
            helper.RegisterStartupScript(opts.ToString());
            return MvcHtmlString.Create(progbar.ToString());
        }

        /// <summary>
        ///  Register the jQuery UI Accordion plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        public static void Accordion(this AjaxHelper helper, string targetSelector)
        {
            helper.Accordion(targetSelector, null);
        }

        /// <summary>
        ///  Register the jQuery UI Accordion plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        /// <param name="options">The accordion options object</param>
        [Obsolete("Please use Dna().Accordion")]
        public static void Accordion(this AjaxHelper helper, string targetSelector, AccordionOptions options)
        {
            helper.jQuery(targetSelector, "accordion", options);
        }

        /// <summary>
        /// Show the simple dialog when the trigger element click.
        /// </summary>
        /// <param name="helpler">The ajax helper object</param>
        /// <param name="triggerID">The trigger element id.</param>
        /// <param name="title">Specified the title of the dialog.</param>
        /// <param name="message">Specified the message shows on the dialog.</param>
        /// <returns>The dialog html result.</returns>
        public static MvcHtmlString Dialog(this AjaxHelper helpler, string triggerID, string title, string message, bool modal)
        {
            return helpler.Dialog(triggerID, DomEvents.Click, title, message, "", "", "", modal);
        }

        /// <summary>
        /// Show the simple dialog when the trigger element click.
        /// </summary>
        /// <param name="helper">The ajax helper object</param>
        /// <param name="triggerID">The trigger element id.</param>
        /// <param name="title">Specified the title of the dialog.</param>
        /// <param name="body">The dialog body.</param>
        /// <param name="okText">The ok button text.</param>
        /// <param name="cancelText">The cancel button text.</param>
        /// <param name="okScript">The client script of the ok button click.</param>
        /// <param name="modal">Specified the the modal dialog when set to true.</param>
        /// <returns></returns>
        public static MvcHtmlString Dialog(this AjaxHelper helper, string triggerID, string title, string body, string okText, string cancelText, string okScript, bool modal)
        {
            return helper.Dialog(triggerID, DomEvents.Click, title, body, okText, cancelText, okScript, modal);
        }

        /// <summary>
        /// Create the dialog Html element and register the jQuery dialog scripts.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="triggerID">Specified which element should show the dialog.</param>
        /// <param name="triggerEvent">Specified which event of the element should trigger the dialog</param>
        /// <param name="title">Specified the title of the dialog.</param>
        /// <param name="body">Specified the dialog body text or html</param>
        /// <param name="okText">Specified the dialog OK button text.</param>
        /// <param name="cancelText">Specified the dialog Cancel button text.</param>
        /// <param name="okScript">Scpified the client scripts when the OK button click.</param>
        /// <returns></returns>
        public static MvcHtmlString Dialog(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string title, string body, string okText, string cancelText, string okScript, bool modal)
        {
            if (string.IsNullOrEmpty(triggerID))
                throw new ArgumentNullException("triggerID");

            if (string.IsNullOrEmpty(body))
                throw new ArgumentNullException("body");

            TagBuilder dlg = new TagBuilder("div");
            string id = Guid.NewGuid().ToString().Substring(0, 5);

            OptionBuilder buttons = new OptionBuilder();
            bool hasButton = false;

            if (!string.IsNullOrEmpty(okText))
            {
                string formatOKText = okText;
                if ((!formatOKText.StartsWith("\"")) && (!formatOKText.StartsWith("'")))
                    formatOKText = "\"" + formatOKText + "\"";
                hasButton = true;
                buttons.AddFunctionOption(formatOKText, okScript + "$(this).dialog(\"close\");");
            }

            if (!string.IsNullOrEmpty(cancelText))
            {
                string formatCancelText = cancelText;
                if ((!formatCancelText.StartsWith("\"")) && (!formatCancelText.StartsWith("'")))
                    formatCancelText = "\"" + formatCancelText + "\"";
                hasButton = true;
                buttons.AddFunctionOption(formatCancelText, "$(this).dialog(\"close\");");
            }

            dlg.InnerHtml = body;
            //dlg.GenerateId(id);
            dlg.Attributes.Add("id", id);
            dlg.Attributes.Add("style", "display:none");
            var opts = new DialogOptions()
            {
                Title = title,
                ShowModal = modal,
                bgiFrame = true
            };

            if (hasButton)
                opts.Buttons = buttons;

            helper.Dialog(id, triggerID, triggerEvent, opts);
            return MvcHtmlString.Create(dlg.ToString());
        }

        /// <summary>
        /// Register the jQuery UI Dialog plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="dialogElementID">Specified the dialog body element id</param>
        /// <param name="triggerID">Specified the element to trigger the dialog.</param>
        /// <param name="triggerEvent">Specified which event of the element should trigger the dialog</param>
        /// <param name="options">The dialog options object</param>
        public static void Dialog(this AjaxHelper helper, string dialogElementID, string triggerID, DomEvents triggerEvent, DialogOptions options)
        {
            if (string.IsNullOrEmpty(dialogElementID))
                throw new ArgumentNullException("id");

            if (string.IsNullOrEmpty(triggerID))
                throw new ArgumentNullException("triggerID");

            if (options == null)
                throw new ArgumentNullException("options");

            StringBuilder scripts = new StringBuilder();
            string dlgID = "$(\"#" + dialogElementID + "\")";

            if (options != null)
                options.OnClose = options.OnClose + dlgID + ".dialog('destroy');";

            scripts.Append("$(\"")
                        .Append(triggerID)
                        .Append("\").bind(\"")
                        .Append(triggerEvent.ToString().ToLower())
                        .Append("\",function(){")
                        .Append(dlgID)
                        .Append(".dialog(")
                        .Append(Options(options))
                        .Append(");")
                        .Append("});");

            helper.RegisterStartupScript(scripts.ToString());

        }

        public static MvcHtmlString Slider(this AjaxHelper helper, string name)
        {
            return Slider(helper, name, new SliderOptions() { EnabledAnimate = true });
        }

        public static MvcHtmlString Slider(this AjaxHelper helper, string name, int value)
        {
            return Slider(helper, name, new SliderOptions() { Value = value, EnabledAnimate = true });
        }

        public static MvcHtmlString Slider(this AjaxHelper helper, string name, SliderOptions options)
        {
            TagBuilder hidden = new TagBuilder("input");
            hidden.GenerateId(name);
            hidden.MergeAttribute("name", name);
            string sliderName = hidden.Attributes["id"] + "_slider";
            TagBuilder sliderContainer = new TagBuilder("div");
            sliderContainer.Attributes.Add("id", sliderName);

            hidden.MergeAttribute("type", "hidden");
            if (options != null)
            {
                hidden.MergeAttribute("value", options.Value.ToString());

                if (options.Height.HasValue)
                    sliderContainer.MergeAttribute("style", "height:" + options.Height.ToString()+"px;");
                if (options.Width.HasValue)
                    sliderContainer.MergeAttribute("style", "width:" + options.Width.ToString()+"px;");

                sliderContainer.InnerHtml = hidden.ToString();

                if (!string.IsNullOrEmpty(options.FillValueTo))
                    options.OnSliding = options.OnSliding + "$(\"#" + options.FillValueTo + "\").val(ui.value);";

                if (!string.IsNullOrEmpty(options.FillTextTo))
                    options.OnSliding = options.OnSliding + "$(\"#" + options.FillTextTo + "\").text(ui.value);";

                options.OnSliding = options.OnSliding + "$(\"#" + hidden.Attributes["id"] + "\").val(ui.value);";

                var jscripts = new jQueryScriptBuilder("#" + sliderName, "slider");

                jscripts.AddOptions(options);

                if (options.Orientation != DNA.Mvc.jQuery.Orientation.Notset)
                    jscripts.AddOption("orientation", options.Orientation.ToString().ToLower(), true);

                if (options.Range != Ranges.Notset)
                    jscripts.AddOption("range", options.Range.ToString().ToLower(), true);

                helper.RegisterStartupScript(jscripts.ToString());
                //helper.jQuery("#" + name + "_slider", "slider", options);
            }
            else
                helper.jQuery("#" + sliderName, "slider");
            return MvcHtmlString.Create(sliderContainer.ToString());
        }

        /// <summary>
        /// Returns the jQuery UI datePicker tag
        /// </summary>
        /// <param name="helper">The ajax helper object</param>
        /// <param name="name">The name of the datepicker</param>
        /// <returns>The html tag of the datepicker</returns>
        public static MvcHtmlString DatePicker(this AjaxHelper helper, string name)
        {
            return DatePicker(helper, name, null);
        }

        /// <summary>
        /// Returns the jQuery UI DatePicker tag and register the jQuery script.
        /// </summary>
        /// <param name="helper">The ajax helper objec.t</param>
        /// <param name="name">The name of the datepicker</param>
        /// <param name="value">The init value of the datepicker.</param>
        /// <returns>The html tag of the datepicker</returns>
        public static MvcHtmlString DatePicker(this AjaxHelper helper, string name, DateTime value)
        {
            return helper.DatePicker(name, new DatePickerOptions() { Value = value });
        }

        public static MvcHtmlString DatePicker(this AjaxHelper helper, string name, DatePickerOptions options)
        {
            if (options != null)
            {
                string format = "MM-dd-yyyy";
                if (!string.IsNullOrEmpty(options.DateFormatString))
                    format = options.DateFormatString;
                else
                    if (!string.IsNullOrEmpty(options.DefaultDateString))
                        format = options.DefaultDateString;

                var opts = new jQueryScriptBuilder("#" + name, "datepicker");
                opts.AddOptions(options);
                var initScripts = new StringBuilder();
                var html = MvcHtmlString.Empty;

                if (options.DisplayMode == DatePickerDisplayModes.Calendar)
                {
                    StringBuilder selectScripts = new StringBuilder();
                    selectScripts.Append("$('#")
                                            .Append(name)
                                            .Append("').val($('#")
                                            .Append(name)
                                            .Append("_datepicker').datepicker('getDate'));");
                    options.OnSelect += selectScripts.ToString();

                    if (options.Value.HasValue)
                    initScripts.Append("$('#")
                      .Append(name)
                      .Append("_datepicker').datepicker('setDate','")
                      .Append(options.Value.Value.ToString(format))
                      .Append("');");

                    var calendar = new TagBuilder("div");
                    calendar.Attributes.Add("id", name + "_datepicker");
                    calendar.InnerHtml = "<input type='hidden' value='" +(options.Value.HasValue ? options.Value.Value.ToString(format) : DateTime.UtcNow.ToString(format)) + "' id='" + name + "' />";
                    html = MvcHtmlString.Create(calendar.ToString());
                }
                else
                {
                    html = helper.TextBox(name, "ui-icon ui-icon-calendar", 200);
                }
                if (!string.IsNullOrEmpty(options.ButtonImageUrl))
                    opts.AddOption("buttonImage", options.ButtonImageUrl, true);

                if ((options.DayNames != null) && (options.DayNames.Length > 0))
                    opts.AddOption("dayNames", options.DayNames);

                if ((options.MinDayNames != null) && (options.MinDayNames.Length > 0))
                    opts.AddOption("dayNamesMin", options.MinDayNames);

                if ((options.ShortDayNames != null) && (options.ShortDayNames.Length > 0))
                    opts.AddOption("dayNamesShort", options.ShortDayNames);

                if ((options.MonthNames != null) && (options.MonthNames.Length > 0))
                    opts.AddOption("monthNames", options.MonthNames);

                if ((options.MonthShortNames != null) && (options.MonthShortNames.Length > 0))
                    opts.AddOption("monthNamesShort", options.MonthShortNames);

                if (!string.IsNullOrEmpty(options.DateFormatString))
                    opts.AddOption("dateFormat", GetjQueryDateFormat(options.DateFormatString), true);

                if (!string.IsNullOrEmpty(options.AnotherFormatString))
                    opts.AddOption("altFormat", GetjQueryDateFormat(options.AnotherFormatString), true);

                if (options.MaxDateValue.HasValue)
                    opts.AddOption("maxDate", options.MaxDateValue.Value.ToString(format),true);

                if (options.MinDateValue.HasValue)
                    opts.AddOption("minDate", options.MinDateValue.Value.ToString(format), true);
                if (!string.IsNullOrEmpty(options.LocID))
                {
                    initScripts.Append("$.datepicker.setDefaults($.datepicker.regional['")
                                      .Append(options.LocID)
                                      .Append("']);");
                    helper.RegisterStartupScript(initScripts.ToString());
                }

                //if (options.DisplayMode == DatePickerDisplayModes.Calendar)

                //helper.jQuery("#" + name + "_datepicker", "datepicker", opts);
                //else
                //    helper.jQuery("#" + name, "datepicker", opts);
                helper.RegisterStartupScript(opts.ToString());
                if (options.Value.HasValue)
                {

                    
                    string dateStr = options.Value.Value.ToString(format);

                    helper.RegisterStartupScript("$(\"#" + name + "\").datepicker('setDate','" + dateStr + "');");
                }
                return html;
            }
            else
            {
                helper.jQuery("#" + name, "datepicker");
                return helper.TextBox(name, "ui-icon ui-icon-calendar", 200);
            }
        }

        private static string GetjQueryDateFormat(string format)
        {
            string formatted = format;
            //Format year
            if (formatted.IndexOf("yy") > -1)
                formatted = formatted.Replace("yy", "y");

            //if (formatted.IndexOf("yy") > -1)
            //    formatted = formatted.Replace("yy", "y");

            if (formatted.IndexOf("MMMM") > -1)
                formatted = formatted.Replace("MMMM", "MM");
            else
            {
                if (formatted.IndexOf("MMM") > -1)
                    formatted = formatted.Replace("MMM", "M");
                else
                {
                    if (formatted.IndexOf("MM") > -1)
                        formatted = formatted.Replace("MM", "mm");
                    else
                        if (formatted.IndexOf("M") > -1)
                            formatted = formatted.Replace("M", "m");
                }
            }

            if (formatted.IndexOf("dddd") > -1)
                formatted = formatted.Replace("dddd", "DD");

            if (formatted.IndexOf("ddd") > -1)
                formatted = formatted.Replace("ddd", "D");

            return formatted;
        }

        /// <summary>
        /// Register the jQuery UI Sortable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        /// <param name="options">The sortable options object</param>
        public static void Sortable(this AjaxHelper helper, string targetSelector, SortableOptions options)
        {
            //helper.jQuery(targetSelector, "sortable", options);

            if (options != null)
            {
                string _sel = targetSelector;
                
                if (!targetSelector.StartsWith(".") && (!targetSelector.StartsWith("#")))
                    _sel = "#" + targetSelector;

                var opts = new jQueryScriptBuilder(_sel, "sortable", options);

                if (options.ContainsIn != Containers.NotSet)
                {
                    if (options.ContainsIn != Containers.Customize)
                        opts.AddOption("containment", options.ContainsIn.ToString().ToLower(), true);
                }
                else
                {
                    if (!string.IsNullOrEmpty(options.Container))
                        opts.AddOption("containment", options.Container, true);
                }


                if (options.DragOrientation != Orientation.Notset)
                {
                    if (options.DragOrientation == Orientation.Horizontal)
                        opts.AddOption("axis", "x", true);
                    else
                        opts.AddOption("axis", "y", true);
                }

                //switch (options.RevertMode)
                //{
                //    case RevertModes.Original:
                //        opts.AddOption("revert", true);
                //        break;
                //    case RevertModes.NotSet:
                //        break;
                //    default:
                //        opts.AddOption("revert", options.RevertMode.ToString().ToLower(), true);
                //        break;
                //}

                //if (!string.IsNullOrEmpty(options.GroupName) && (options.GroupMinZIndex != 0))
                //    opts.AddOption("stack", "{ group:'" + options.GroupName + "',min:" + options.GroupMinZIndex.ToString() + "}", false);

                if (string.IsNullOrEmpty(options.CustomHelper))
                {
                    if (options.DragHelper != Helpers.NotSet)
                        opts.AddOption("helper", options.DragHelper.ToString().ToLower(), true);
                }
                else
                    opts.AddFunctionOption("helper", "return $(\"" + options.CustomHelper + "\");", new string[] { "event" });
                helper.RegisterStartupScript(opts.ToString());
            }
            else
                helper.jQuery(targetSelector, "sortable");
        }

        /// <summary>
        ///  Register the jQuery UI Sortable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        public static void Sortable(this AjaxHelper helper, string targetSelector)
        {
            helper.Sortable(targetSelector, null);
        }

        public static void Selectable(this AjaxHelper helper, string targetSelector)
        {
            helper.Selectable(targetSelector, null);
        }

        public static void Selectable(this AjaxHelper helper, string targetSelector, SelectableOptions options)
        {
            helper.jQuery(targetSelector, "selectable", options);
        }


        /// <summary>
        /// Register the jQuery UI Draggable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        public static void Draggable(this AjaxHelper helper, string targetSelector)
        {
            helper.Draggable(targetSelector, null);
        }

        /// <summary>
        /// Register the jQuery UI Draggable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        /// <param name="options">The draggable options object</param>
        public static void Draggable(this AjaxHelper helper, string targetSelector, DraggableOptions options)
        {

            if (options != null)
            {
                string _sel = targetSelector;
                if (!targetSelector.StartsWith(".") && (!targetSelector.StartsWith("#")))
                    _sel = "#" + targetSelector;

                var opts = new jQueryScriptBuilder(_sel, "draggable", options);
                if (options.ContainmentBounds != null)
                {
                    opts.AddOption("containment", options.ContainmentBounds);
                }
                else
                {
                    if (options.ContainsIn != Containers.NotSet)
                    {
                        if (options.ContainsIn != Containers.Customize)
                            opts.AddOption("containment", options.ContainsIn.ToString().ToLower(), true);
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(options.Container))
                            opts.AddOption("containment", options.Container, true);
                    }
                }

                if (options.DragOrientation != Orientation.Notset)
                {
                    if (options.DragOrientation == Orientation.Horizontal)
                        opts.AddOption("axis", "x", true);
                    else
                        opts.AddOption("axis", "y", true);
                }

                switch (options.RevertMode)
                {
                    case RevertModes.Original:
                        opts.AddOption("revert", true);
                        break;
                    case RevertModes.NotSet:
                        break;
                    default:
                        opts.AddOption("revert", options.RevertMode.ToString().ToLower(), true);
                        break;
                }

                if (!string.IsNullOrEmpty(options.GroupName) && (options.GroupMinZIndex != 0))
                    opts.AddOption("stack", "{ group:'" + options.GroupName + "',min:" + options.GroupMinZIndex.ToString() + "}", false);

                if (string.IsNullOrEmpty(options.CustomHelper))
                {
                    if (options.DragHelper != Helpers.NotSet)
                        opts.AddOption("helper", options.DragHelper.ToString().ToLower(), true);
                }
                else
                    opts.AddFunctionOption("helper", "return $(\"" + options.CustomHelper + "\");", new string[] { "event" });
                helper.RegisterStartupScript(opts.ToString());
            }
            else
                helper.jQuery(targetSelector, "draggable");


        }

        /// <summary>
        /// Register the jQuery UI Droppable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        /// <param name="options">The draggable options object</param>
        public static void Droppable(this AjaxHelper helper, string targetSelector, DroppableOptions options)
        {
            helper.jQuery(targetSelector, "droppable", options);
        }

        /// <summary>
        /// Register the jQuery UI Droppable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        public static void Droppable(this AjaxHelper helper, string targetSelector)
        {
            helper.Droppable(targetSelector, null);
        }

        /// <summary>
        ///  Register the jQuery UI Resizable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        public static void Resizable(this AjaxHelper helper, string targetSelector)
        {
            helper.Resizable(targetSelector, null);
        }

        /// <summary>
        /// Register the jQuery UI Resizable plugin script.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="targetSelector">The jQuery selector</param>
        /// <param name="options">The resizable options object.</param>
        public static void Resizable(this AjaxHelper helper, string targetSelector, ResizableOptions options)
        {
            helper.jQuery(targetSelector, "resizable", options);
        }

        #endregion

        #region jQuery Ajax

        /// <summary>
        /// Returns the low level ajax scripts for jQuery
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static string GeneratejQueryAjaxScripts(this AjaxHelper helper, jQueryAjaxOptions options)
        {
            if (options == null)
                throw new ArgumentNullException("options");

            if (string.IsNullOrEmpty(options.Url))
                throw new ArgumentNullException("Url");

            StringBuilder scripts = new StringBuilder();

            if (!string.IsNullOrEmpty(options.TriggerID))
                scripts.Append("$(\"#")
                    .Append(options.TriggerID)
                    .Append("\").bind(\"")
                    .Append(options.TriggerEvent.ToString().ToLower())
                    .Append("\",function(){");

            scripts.Append("$.ajax(");

            if (!string.IsNullOrEmpty(options.Confirm))
                options.OnBeforeSend = "if (!confirm(\"" + options.Confirm + "\")) return false;" + options.OnBeforeSend;

            string targetID = options.UpdateTargetID;

            if (!string.IsNullOrEmpty(options.LoadingElementID))
            {
                string loadingID = "$(\"#" + options.LoadingElementID + "\")";
                options.OnBeforeSend += targetID + ".html(\"\");" + targetID + ".append(" + loadingID + ").show();";
                options.OnComplete += "$(\"body\").append(" + loadingID + ");" + loadingID + ".hide();";
            }
            else
            {
                if (options.AutoBlocking)
                {
                    options.OnBeforeSend += "uiHelper.blockUI($(\"";
                    options.OnSuccess += "uiHelper.unblockUI($(\"";
                    if (!string.IsNullOrEmpty(options.UpdateTargetID))
                    {
                        options.OnBeforeSend += "#" + targetID;// "\"" + options.UpdateTargetID + "\"";
                        options.OnSuccess += "#" + targetID;// "\"" + options.UpdateTargetID + "\"";
                    }
                    else
                    {
                        options.OnBeforeSend += "body";
                        options.OnSuccess += "body";
                    }
                    options.OnBeforeSend += "\"));";
                    options.OnSuccess += "\"));";
                }
            }

            if (!string.IsNullOrEmpty(options.UpdateTargetID))
            {
                targetID = "$(\"#" + options.UpdateTargetID + "\")";
                switch (options.InsertionMode)
                {
                    case System.Web.Mvc.Ajax.InsertionMode.InsertAfter:
                        options.OnSuccess = targetID + ".append(data);" + options.OnSuccess;
                        break;
                    case System.Web.Mvc.Ajax.InsertionMode.InsertBefore:
                        options.OnSuccess = targetID + ".prepend(data);" + options.OnSuccess;
                        break;
                    case System.Web.Mvc.Ajax.InsertionMode.Replace:
                        options.OnSuccess = "if ($.browser.msie) " + targetID + ".replaceWith('');" + targetID + ".replaceWith(data);" + options.OnSuccess;
                        break;
                }
            }

            if (options.AutoHandlingError)
                options.OnError = "uiHelper.errorHandler(XMLHttpRequest, textStatus, errorThrown);";

            #region paramerters auto binding
            if (options.AutoBindingParameterElement)
            {
                if (options.Data != null)
                {
                    var ep = ObjectHelper.ConvertObjectToDictionary(options.Data);
                    var dataCopy = new OptionBuilder();
                    foreach (string key in ep.Keys)
                    {
                        if (!ep[key].ToString().StartsWith("$"))
                            dataCopy.AddOption(key, "$(\"#" + ep[key].ToString() + "\").val()", false);
                    }
                    options.Data = dataCopy;
                }
            }
            #endregion

            scripts.Append(Options(options))
                        .Append(");");
            if (!string.IsNullOrEmpty(options.TriggerID))
                scripts.Append("});");
            return scripts.ToString();
        }

        /// <summary>
        /// The low level ajax method to load a remote url using an HTTP request.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="options"></param>
        public static void jQueryAjax(this AjaxHelper helper, jQueryAjaxOptions options)
        {
            helper.RegisterStartupScript(helper.GeneratejQueryAjaxScripts(options));
        }

        public static void Load(this AjaxHelper helper, string triggerID, string updateTargetID, string loadingElementID, string url)
        {
            Load(helper, triggerID, updateTargetID, loadingElementID, url, null);
        }

        public static void Load(this AjaxHelper helper, string triggerID, string updateTargetID, string url)
        {
            Load(helper, triggerID, updateTargetID, "", url, null);
        }

        public static void Load(this AjaxHelper helper, string triggerID, string updateTargetID, string url, object elementBinder)
        {
            Load(helper, triggerID, updateTargetID, "", url, elementBinder);
        }

        public static void Load(this AjaxHelper helper, string triggerID, string updateTargetID, string loadingElementID, string url, object elementBinder)
        {
            helper.Load(new jQueryAjaxOptions()
            {
                TriggerID = triggerID,
                UpdateTargetID = updateTargetID,
                LoadingElementID = loadingElementID,
                InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace,
                Url = url,
                AutoBindingParameterElement = (elementBinder != null),
                Data = elementBinder
            });
        }

        public static void Load(this AjaxHelper helper, jQueryAjaxOptions options)
        {
            options.HttpMethod = "GET";
            jQueryAjax(helper, options);
        }

        public static void Post(this AjaxHelper helper, string triggerID, string updateTargetID, string url)
        {
            Post(helper, triggerID, updateTargetID, "", url, null);
        }

        public static void Post(this AjaxHelper helper, string triggerID, string updateTargetID, string url, object elementBinder)
        {
            Post(helper, triggerID, updateTargetID, "", url, elementBinder);
        }

        public static void Post(this AjaxHelper helper, string triggerID, string updateTargetID, string loadingElementID, string url, object elementBinder)
        {
            helper.Post(new jQueryAjaxOptions()
            {
                TriggerID = triggerID,
                UpdateTargetID = updateTargetID,
                LoadingElementID = loadingElementID,
                InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace,
                Url = url,
                AutoBindingParameterElement = (elementBinder != null),
                Data = elementBinder
            });
        }


        public static void Post(this AjaxHelper helper, jQueryAjaxOptions options)
        {
            options.HttpMethod = "POST";
            jQueryAjax(helper, options);
        }

        ///// <summary>
        ///// Load the action result into target element when the tarigger element click.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="action">The name of the action.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, string action)
        //{
        //    helper.Load(triggerID, DomEvents.Click, targetID, helper.ActionUrl(action, null, null), null, null);
        //}

        ///// <summary>
        /////  Load the action result into target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the load method</param>
        ///// <param name="action">The name of the action.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, DomEvents triggerEvent, string action)
        //{
        //    helper.Load(triggerID, triggerEvent, targetID, helper.ActionUrl(action, null, null), null, null);
        //}

        ///// <summary>
        /////  Load the action result into target element when the tarigger element click.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller ,set to null or empty to use current controller.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, string action, string controller)
        //{
        //    helper.Load(triggerID, DomEvents.Click, targetID, helper.ActionUrl(action, controller, null), null, null);
        //}

        ///// <summary>
        /////  Load the action result into target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the load method</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller ,set to null or empty to use current controller.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, DomEvents triggerEvent, string action, string controller)
        //{
        //    helper.Load(triggerID, triggerEvent, targetID, helper.ActionUrl(action, controller, null), null, null);
        //}

        ///// <summary>
        /////  Load the action result into target element when the tarigger element click.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, string action, object routeData)
        //{
        //    helper.Load(triggerID, DomEvents.Click, targetID, helper.ActionUrl(action, null, routeData), null, null);
        //}

        ///// <summary>
        /////  Load the action result into target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the load method</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, DomEvents triggerEvent, string action, object routeData)
        //{
        //    helper.Load(triggerID, triggerEvent, targetID, helper.ActionUrl(action, null, routeData), null, null);
        //}

        ///// <summary>
        /////  Load the action result into target element when the tarigger element click.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller ,set to null or empty to use current controller.</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, string action, string controller, object routeData)
        //{
        //    helper.Load(triggerID, DomEvents.Click, targetID, helper.ActionUrl(action, controller, routeData), null, null);
        //}

        ///// <summary>
        /////  Load the action result into target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the load method</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller ,set to null or empty to use current controller.</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, DomEvents triggerEvent, string action, string controller, object routeData)
        //{
        //    helper.Load(triggerID, triggerEvent, targetID, helper.ActionUrl(action, controller, routeData), null,null);
        //}

        //public static void Load(this AjaxHelper helper, string triggerID, string targetID, string action, string controller, IDictionary<string, string> elementParams)
        //{
        //    helper.Load(triggerID, DomEvents.Click, targetID, helper.ActionUrl(action, controller, null),null, elementParams);
        //}


        ///// <summary>
        ///// Load HTML from a remote file and inject it into the DOM.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="url">Specified the url of the Html to load</param>
        ///// <param name="elementParams">Specified the data that will be send to the server.</param>
        ///// <param name="clientCallback">The function called when the ajax request is complete (not necessarily success). </param>
        ///// <remarks></remarks>
        //public static void Load(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string targetID, string url, string clientCallback, object elementParams)
        //{
        //    if (string.IsNullOrEmpty(targetID))
        //        throw new ArgumentNullException("targetID");

        //    if (string.IsNullOrEmpty(triggerID))
        //        throw new ArgumentNullException("triggerID");

        //    StringBuilder scripts = new StringBuilder();
        //    scripts.Append("$(\"#")
        //        .Append(triggerID)
        //        .Append("\").bind(\"")
        //        .Append(triggerEvent.ToString().ToLower())
        //        .Append("\",function(){")
        //        .Append("$(\"#")
        //        .Append(targetID)
        //        .Append("\").load(\"")
        //        .Append(url)
        //        .Append("\"");

        //    scripts.Append(",");

        //    if (elementParams != null)
        //    {
        //        scripts.Append("{");
        //        var ep = ObjectHelper.ConvertObjectToDictionary(elementParams);
        //        int i = 0;
        //        foreach (string key in ep.Keys)
        //        {
        //            if (i > 0)
        //                scripts.Append(",");
        //            scripts.Append(key)
        //                        .Append(":")
        //                        .Append("$(\"#")
        //                        .Append(ep[key])
        //                        .Append("\").val()");
        //            i++;
        //        }
        //        scripts.Append("}");
        //    }
        //    else
        //        scripts.Append("{}");

        //    if (!string.IsNullOrEmpty(clientCallback))
        //    {
        //        if (!clientCallback.StartsWith("function"))
        //            scripts.Append(",function(responseText, textStatus, XMLHttpRequest){")
        //                        .Append(clientCallback)
        //                        .Append("}");
        //        else
        //            scripts.Append(",").Append(clientCallback);
        //    }
        //    scripts.Append(");")
        //    .Append("}")
        //    .Append(");");
        //    helper.RegisterStartupScript(scripts.ToString());
        //}

        ///// <summary>
        ///// Execute the Controller action and display the action result to the specified target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the post method</param>
        ///// <param name="targetID">Specifie the element which to display the postback html result.</param>
        ///// <param name="action">The name of the action.</param>
        //public static void Post(this AjaxHelper helper, string triggerID, string targetID, string action)
        //{
        //    helper.Post(triggerID, targetID, action, null, null);
        //}

        ///// <summary>
        ///// Execute the Controller action and display the action result to the specified target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the post method</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the post method</param>
        ///// <param name="targetID">Specifie the element which to display the postback html result.</param>
        ///// <param name="action">The name of the action.</param>
        //public static void Post(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string targetID, string action)
        //{
        //    helper.Post(triggerID, triggerEvent, targetID, action, null, null);
        //}

        ///// <summary>
        ///// Execute the Controller action and display the action result to the specified target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the post method</param>
        ///// <param name="targetID">Specifie the element which to display the postback html result.</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller</param>
        //public static void Post(this AjaxHelper helper, string triggerID, string targetID, string action, string controller)
        //{
        //    helper.Post(triggerID, targetID, action, controller, null);
        //}

        ///// <summary>
        ///// Execute the Controller action and display the action result to the specified target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the post method</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the post method</param>
        ///// <param name="targetID">Specifie the element which to display the postback html result.</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller</param>
        //public static void Post(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string targetID, string action, string controller)
        //{
        //    helper.Post(triggerID, triggerEvent, targetID, action, controller, null);
        //}

        ///// <summary>
        ///// Execute the Controller action and display the action result to the specified target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the post method</param>
        ///// <param name="targetID">Specifie the element which to display the postback html result.</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        //public static void Post(this AjaxHelper helper, string triggerID, string targetID, string action, string controller, object routeData)
        //{
        //    helper.Post(triggerID, DomEvents.Click, targetID, action, controller, routeData);
        //}

        ///// <summary>
        ///// Execute the Controller action and display the action result to the specified target element.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the post method</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the post method</param>
        ///// <param name="targetID">Specifie the element which to display the postback html result.</param>
        ///// <param name="action">The name of the action.</param>
        ///// <param name="controller">The name of the controller</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        //public static void Post(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string targetID, string action, string controller, object routeData)
        //{
        //    helper.Post(triggerID, triggerEvent, helper.ActionUrl(action, controller, null), routeData, "$('#" + targetID + "').html(data);", AjaxDataTypes.Html);
        //}

        ///// <summary>
        ///// Load a remote page using an HTTP POST request
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the post method</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the post method</param>
        ///// <param name="url">Specified the url to post.</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        ///// <param name="clientCallback">Attach the function when the post method callback</param>
        ///// <param name="type">Type of data to be returned to callback function</param>
        //public static void Post(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string url, object routeData, string clientCallback, AjaxDataTypes type)
        //{
        //    if (string.IsNullOrEmpty(triggerID))
        //        throw new ArgumentNullException("triggerID");

        //    StringBuilder scripts = new StringBuilder();
        //    scripts.Append("$(\"#")
        //                .Append(triggerID)
        //                .Append("\").bind(\"")
        //                .Append(triggerEvent.ToString().ToLower())
        //                .Append(",function(){")
        //        .Append("$.post(\"")
        //        .Append(url)
        //        .Append("\"");

        //    scripts.Append(",");
        //    if (routeData != null)
        //        scripts.Append(Options(routeData));
        //    else
        //        scripts.Append("{}");

        //    if (!string.IsNullOrEmpty(clientCallback))
        //    {
        //        if (!clientCallback.StartsWith("function"))
        //            scripts.Append(",function(data, textStatus){")
        //                        .Append(clientCallback)
        //                        .Append("}");
        //        else
        //            scripts.Append(",").Append(clientCallback);
        //    }

        //    scripts.Append(",\"")
        //                .Append(type.ToString())
        //                .Append("\"")
        //                .Append(");")
        //                .Append("}")
        //                .Append("\");");

        //    helper.RegisterStartupScript(scripts.ToString());
        //}

        ///// <summary>
        ///// Load HTML from a remote file and inject it into the DOM.
        ///// </summary>
        ///// <param name="helper">The ajax helper object</param>
        ///// <param name="triggerID">Specified the element id to trigger the load method</param>
        ///// <param name="triggerEvent">Specified the trigger event type of the element to invoke the load method</param>
        ///// <param name="targetID">Specified the element id to display the load result.</param>
        ///// <param name="url">Specified the url of the Html to load</param>
        ///// <param name="routeData">Specified the data that will be send to the server.</param>
        ///// <param name="clientCallback">The function called when the ajax request is complete (not necessarily success). </param>
        //public static void Get(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string targetID, string url, object routeData, string clientCallback)
        //{
        //    if (string.IsNullOrEmpty(triggerID))
        //        throw new ArgumentNullException("triggerID");

        //    StringBuilder scripts = new StringBuilder();
        //    scripts.Append("$(\"#")
        //                .Append(triggerID)
        //                .Append("\").bind(\"")
        //                .Append(triggerEvent.ToString().ToLower())
        //                .Append(",function(){")
        //        .Append("$.get(\"")
        //        .Append(url)
        //        .Append("\"");

        //    scripts.Append(",");

        //    if (routeData != null)
        //        scripts.Append(Options(routeData));
        //    else
        //        scripts.Append("{}");

        //    if (!string.IsNullOrEmpty(clientCallback))
        //    {
        //        if (!clientCallback.StartsWith("function"))
        //            scripts.Append(",function(data){")
        //                        .Append(clientCallback)
        //                        .Append("}");
        //        else
        //            scripts.Append(",").Append(clientCallback);
        //    }

        //    scripts.Append(");")
        //                .Append("}")
        //                .Append("\");");

        //    helper.RegisterStartupScript(scripts.ToString());
        //}

        /// <summary>
        /// Load JSON data using an HTTP GET request.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="triggerID">Specified the element id to trigger the getJson method</param>
        /// <param name="triggerEvent">Specified the trigger event type of the element to invoke the getJson method</param>
        /// <param name="url">Specified the url to get.</param>
        /// <param name="routeData">Specified the data that will be send to the server.</param>
        /// <param name="clientCallback">Attach the function when the GetJson method callback</param>
        /// <remarks> you can load JSON data located on another domain.</remarks>
        public static void GetJson(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string url, object routeData, string clientCallback)
        {
            if (string.IsNullOrEmpty(triggerID))
                throw new ArgumentNullException("triggerID");

            StringBuilder scripts = new StringBuilder();
            scripts.Append("$(\"#")
                        .Append(triggerID)
                        .Append("\").bind(\"")
                        .Append(triggerEvent.ToString().ToLower())
                        .Append(",function(){")
                .Append("$.getJSON(\"")
                .Append(url)
                .Append("\"");

            scripts.Append(",");

            if (routeData != null)
                scripts.Append(Options(routeData));
            else
                scripts.Append("{}");

            if (!string.IsNullOrEmpty(clientCallback))
            {
                if (!clientCallback.StartsWith("function"))
                    scripts.Append(",function(data){")
                                .Append(clientCallback)
                                .Append("}");
                else
                    scripts.Append(",").Append(clientCallback);
            }

            scripts.Append(");")
                        .Append("}")
                        .Append("\");");

            helper.RegisterStartupScript(scripts.ToString());
        }


        /// <summary>
        /// Loads and executes a JavaScript file using an HTTP GET request.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="triggerID">Specified the element id to trigger the getScript method</param>
        /// <param name="triggerEvent">Specified the trigger event type of the element to invoke the getScript method</param>
        /// <param name="url">Sepcified the url to load the javascript file.</param>
        /// <param name="clientCallback">Attach the function when the GetScript method callback</param>
        public static void GetScript(this AjaxHelper helper, string triggerID, DomEvents triggerEvent, string url, string clientCallback)
        {
            if (string.IsNullOrEmpty(triggerID))
                throw new ArgumentNullException("triggerID");

            StringBuilder scripts = new StringBuilder();
            scripts.Append("$(\"#")
                        .Append(triggerID)
                        .Append("\").bind(\"")
                        .Append(triggerEvent.ToString().ToLower())
                        .Append(",function(){")
                .Append("$.getScript(\"")
                .Append(url)
                .Append("\"");

            if (!string.IsNullOrEmpty(clientCallback))
            {
                if (!clientCallback.StartsWith("function"))
                    scripts.Append(",function(data){")
                                .Append(clientCallback)
                                .Append("}");
                else
                    scripts.Append(",").Append(clientCallback);
            }

            scripts.Append(");")
                        .Append("}")
                        .Append("\");");

            helper.RegisterStartupScript(scripts.ToString());
        }

        private static void OnAjaxEventHelper(AjaxHelper helper, string clientCallback, string method, string arguments)
        {
            if (string.IsNullOrEmpty(clientCallback))
                throw new ArgumentNullException("clientCallback");

            StringBuilder scripts = new StringBuilder();
            scripts.Append("$.")
                        .Append(method)
                        .Append("(");

            if (!clientCallback.StartsWith("function"))
            {
                scripts.Append("funcation(");

                if (string.IsNullOrEmpty(arguments))
                    scripts.Append("){");
                else
                    scripts.Append(arguments)
                                .Append("){");
                scripts.Append(clientCallback)
                            .Append("}");
            }
            else
            {
                scripts.Append(clientCallback);
            }

            scripts.Append(");");
            helper.RegisterStartupScript(scripts.ToString());
        }

        /// <summary>
        /// Attach a function to be executed whenever an AJAX request completes.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="clientCallback">The client call back function to be attached.</param>
        /// <remarks>the client callback function has 3 params
        /// <list>
        /// <item>event - the javascript event object</item>
        /// <item>XMLHttpRequest - The XMLHttpRequest and settings used for that request are passed as arguments to the callback</item>
        /// <item>ajaxOptions</item>
        /// </list>
        /// You can write the function body directily ,this methods will genernate the funcation scripts automatic.
        /// </remarks>
        public static void OnAjaxComplete(this AjaxHelper helper, string clientCallback)
        {
            OnAjaxEventHelper(helper, clientCallback, "ajaxComplete", "event,XMLHttpRequest,ajaxOptions");
        }

        /// <summary>
        /// Attach a function to be executed whenever an AJAX request fails
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="clientCallback">The client call back function to be attached.</param>
        /// <remarks>the client callback function has 4 params
        /// <list>
        /// <item>event - the javascript event object</item>
        /// <item>XMLHttpRequest - The XMLHttpRequest and settings used for that request are passed as arguments to the callback</item>
        /// <item>ajaxOptions</item>
        /// <item>thrownError-an exception object, is passed if an exception occured while processing the request</item>
        /// </list>
        /// You can write the function body directily ,this methods will genernate the funcation scripts automatic.
        /// </remarks>
        public static void OnAjaxError(this AjaxHelper helper, string clientCallback)
        {
            OnAjaxEventHelper(helper, clientCallback, "ajaxError", "event, XMLHttpRequest, ajaxOptions, thrownError");
        }

        /// <summary>
        /// Attach a function to be executed before an AJAX request is sent.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="clientCallback">The client call back function to be attached.</param>
        /// <remarks>the client callback function has 3 params
        /// <list>
        /// <item>event - the javascript event object</item>
        /// <item>XMLHttpRequest - The XMLHttpRequest and settings used for that request are passed as arguments to the callback</item>
        /// <item>ajaxOptions</item>
        /// </list>
        /// You can write the function body directily ,this methods will genernate the funcation scripts automatic.
        /// </remarks>
        public static void OnAjaxSend(this AjaxHelper helper, string clientCallback)
        {
            OnAjaxEventHelper(helper, clientCallback, "ajaxSend", "event, XMLHttpRequest, ajaxOptions");

        }

        /// <summary>
        /// Attach a function to be executed whenever an AJAX request begins and there is none already active.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="clientCallback">The client call back function to be attached.</param>
        public static void OnAjaxStart(this AjaxHelper helper, string clientCallback)
        {
            OnAjaxEventHelper(helper, clientCallback, "ajaxStart", "");
        }

        /// <summary>
        /// Attach a function to be executed whenever all AJAX requests have ended.
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="clientCallback">The client call back function to be attached.</param>
        public static void OnAjaxStop(this AjaxHelper helper, string clientCallback)
        {
            OnAjaxEventHelper(helper, clientCallback, "ajaxStop", "");
        }

        /// <summary>
        /// Attach a function to be executed whenever an AJAX request completes successfully
        /// </summary>
        /// <param name="helper">The ajax helper object.</param>
        /// <param name="clientCallback">The client call back function to be attached.</param>
        /// <remarks>the client callback function has 3 params
        /// <list>
        /// <item>event - the javascript event object</item>
        /// <item>XMLHttpRequest - The XMLHttpRequest and settings used for that request are passed as arguments to the callback</item>
        /// <item>ajaxOptions</item>
        /// </list>
        /// You can write the function body directily ,this methods will genernate the funcation scripts automatic.
        /// </remarks>
        public static void OnAjaxSuccess(this AjaxHelper helper, string clientCallback)
        {
            OnAjaxEventHelper(helper, clientCallback, "ajaxSuccess", "event, XMLHttpRequest, ajaxOptions");
        }
        #endregion

        #region Helper methods

        public static string JSON(object obj)
        {
            return (new JavaScriptSerializer()).Serialize(obj);
        }

        private static string Options(object obj)
        {
            if (obj is OptionBuilder)
                return ((OptionBuilder)obj).ToString();

            OptionBuilder builder = new OptionBuilder();
            builder.AddOptions(obj);
            return builder.ToString();
        }

        //internal static string ActionUrl(this AjaxHelper helper)
        //{
        //    return helper.ActionUrl(null, null, null);
        //}

        //internal static string ActionUrl(this AjaxHelper helper, string action)
        //{
        //    return helper.ActionUrl(action, null, null);
        //}

        //internal static string ActionUrl(this AjaxHelper helper, string action, object routeData)
        //{
        //    return helper.ActionUrl(action, null, routeData);
        //}

        internal static string ActionUrl(this AjaxHelper helper, string action, string controllerName, object routeData)
        {
            UrlHelper _urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string _action = string.IsNullOrEmpty(action) ? helper.ViewContext.RouteData.Values["action"].ToString() : action;
            string _controller = string.IsNullOrEmpty(controllerName) ? helper.ViewContext.RouteData.Values["controller"].ToString() : controllerName;
            if (routeData != null)
                return _urlHelper.Action(_action, _controller, routeData);
            else
                return _urlHelper.Action(_action, _controller);
        }

        #endregion
    }
}
